package com.dfy.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dfy.entity.Spot;
import com.dfy.mapper.SpotMapper;
import com.dfy.service.SpotService;
import com.dfy.dto.SpotDTO;
import com.dfy.dto.SpotResponse;
import com.dfy.dto.SpotRequest;
import com.dfy.dto.HomePageResponse;
import com.dfy.exception.BusinessException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.util.StringUtils;
import com.fasterxml.jackson.core.type.TypeReference;
import java.util.Collections;
import java.math.BigDecimal;
import java.util.Map;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.dfy.entity.SpotDetail;
import com.dfy.entity.SpotFacility;
import com.dfy.mapper.SpotDetailMapper;
import com.dfy.mapper.SpotFacilityMapper;
import com.dfy.dto.SpotDetailDTO;
import java.util.ArrayList;
import com.dfy.dto.SpotFacilityRequest;
import com.dfy.dto.SpotFacilityDTO;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import java.util.Arrays;
import com.dfy.dto.FacilityDTO;
import com.dfy.dto.SpotDetailResponse;
import java.util.LinkedHashMap;
import org.springframework.beans.BeanUtils;
import com.dfy.mapper.OrderMapper;
import com.dfy.mapper.UserFavoriteMapper;

@Service
@Slf4j
public class SpotServiceImpl extends ServiceImpl<SpotMapper, Spot> implements SpotService {

    @Autowired
    private SpotMapper spotMapper;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private SpotDetailMapper spotDetailMapper;

    @Autowired
    private SpotFacilityMapper spotFacilityMapper;

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private UserFavoriteMapper userFavoriteMapper;

    @Override
    public SpotDetailResponse getSpotDetail(Long id) {
        // 使用自定义的查询方法获取景点信息
        Spot spot = spotMapper.selectSpotById(id);
        if (spot == null) {
            throw new BusinessException(404, "景点不存在");
        }

        SpotDetail spotDetail = spotDetailMapper.selectOne(
            new LambdaQueryWrapper<SpotDetail>()
                .eq(SpotDetail::getSpotId, id)
        );

        // 转换详情对象
        SpotDetailDTO detailDTO = spotDetail != null ? SpotDetailDTO.builder()
            .id(spotDetail.getId())
            .spotId(spotDetail.getSpotId())
            .description(spotDetail.getDescription())
            .notice(spotDetail.getNotice())
            .trafficInfo(spotDetail.getTrafficInfo())
            .categoryDescription(spotDetail.getCategoryDescription())
            .createdAt(spotDetail.getCreatedAt())
            .updatedAt(spotDetail.getUpdatedAt())
            .build() : null;

        // 获取景点设施
        List<FacilityDTO> facilities = getFacilities(id);

        // 获取相关景点
        List<SpotResponse> relatedSpots = getRelatedSpots(spot);

        // 构建响应
        return SpotDetailResponse.builder()
            .id(spot.getId())
            .name(spot.getName())
            .description(spot.getDescription())
            .location(spot.getLocation())
            .price(spot.getPrice())
            .rating(spot.getRating())
            .imageUrls(parseImageUrls(spot.getImageUrls()))
            .category_type(spot.getCategoryType())
            .type(spot.getType())
            .contact_phone(spot.getContactPhone())
            .opening_hours(spot.getOpeningHours())
            .position_left(spot.getPositionLeft())
            .position_top(spot.getPositionTop())
            .status(spot.getStatus())
            .tags(parseTags(spot.getTags()))
            .facilities(facilities)
            .related_spots(relatedSpots)
            .detail(detailDTO)
            .created_at(spot.getCreatedAt())
            .updated_at(spot.getUpdatedAt())
            .build();
    }

    private List<String> parseImageUrls(String imageUrlsStr) {
        if (StringUtils.hasText(imageUrlsStr)) {
            try {
                if (imageUrlsStr.startsWith("[")) {
                    return objectMapper.readValue(imageUrlsStr, new TypeReference<List<String>>() {});
                } else {
                    return Collections.singletonList(imageUrlsStr);
                }
            } catch (Exception e) {
                log.error("解析图片URL失败: {}", e.getMessage());
            }
        }
        return Collections.emptyList();
    }

    private List<String> parseTags(String tagsStr) {
        if (StringUtils.hasText(tagsStr)) {
            try {
                return Arrays.asList(tagsStr.split(","));
            } catch (Exception e) {
                log.error("解析标签失败: {}", e.getMessage());
            }
        }
        return Collections.emptyList();
    }

    private List<FacilityDTO> getFacilities(Long spotId) {
        List<SpotFacility> facilities = spotFacilityMapper.selectList(
            new LambdaQueryWrapper<SpotFacility>()
                .eq(SpotFacility::getSpotId, spotId)
        );

        return facilities.stream()
            .map(facility -> FacilityDTO.builder()
                .id(facility.getId())
                .spotId(facility.getSpotId())
                .facilityName(facility.getFacilityName())
                .facilityValue(facility.getFacilityValue())
                .createdAt(facility.getCreatedAt())
                .updatedAt(facility.getUpdatedAt())
                .build())
            .collect(Collectors.toList());
    }

    private List<SpotResponse> getRelatedSpots(Spot spot) {
        // 获取同类型的其他景点
        List<Spot> relatedSpots = list(new LambdaQueryWrapper<Spot>()
            .eq(Spot::getType, spot.getType())
            .ne(Spot::getId, spot.getId())
            .last("LIMIT 6"));

        return relatedSpots.stream()
            .map(this::convertToSpotResponse)
            .collect(Collectors.toList());
    }

    private SpotResponse convertToSpotResponse(Spot spot) {
        // 获景点详情
        SpotDetail spotDetail = spotDetailMapper.selectOne(
            new LambdaQueryWrapper<SpotDetail>()
                .eq(SpotDetail::getSpotId, spot.getId())
        );

        return SpotResponse.builder()
            .id(spot.getId())
            .name(spot.getName())
            .description(spot.getDescription())
            .location(spot.getLocation())
            .price(spot.getPrice())
            .rating(spot.getRating())
            .imageUrls(parseImageUrls(spot.getImageUrls()))
            .type(spot.getType())
            .category_type(spot.getCategoryType())
            .status(spot.getStatus())
            .created_at(spot.getCreatedAt())
            .updated_at(spot.getUpdatedAt())
            .spot_detail(spotDetail != null ? spotDetail.getDescription() : null)
            .notice(spotDetail != null ? spotDetail.getNotice() : null)
            .traffic_info(spotDetail != null ? spotDetail.getTrafficInfo() : null)
            .category_description(spotDetail != null ? spotDetail.getCategoryDescription() : null)
            .build();
    }

    @Override
    public HomePageResponse getHomePageData(String keyword, String type, String categoryType) {
        // 构建基本查询条件
        LambdaQueryWrapper<Spot> queryWrapper = new LambdaQueryWrapper<>();
        // queryWrapper.eq(Spot::getStatus, "");
        
        // 添���搜索条件
        if (StringUtils.hasText(keyword)) {
            queryWrapper.and(w -> w.like(Spot::getName, keyword)
                .or()
                .like(Spot::getDescription, keyword)
                .or()
                .like(Spot::getLocation, keyword));
        }
        
        // 添加类型筛选
        if (StringUtils.hasText(type)) {
            queryWrapper.eq(Spot::getType, type);
        }
        
        // 添加分类筛选
        if (StringUtils.hasText(categoryType)) {
            queryWrapper.eq(Spot::getCategoryType, categoryType);
        }

        // 获取搜索结果
        List<Spot> spots = list(queryWrapper);

        // 如果没有找到匹配的结果，直接返回空数据
        if (spots.isEmpty()) {
            return HomePageResponse.builder()
                .hotSpots(Collections.emptyList())
                .newSpots(Collections.emptyList())
                .categories(Collections.emptyMap())
                .types(Collections.emptyMap())
                .priceRanges(Collections.emptyMap())
                .total(0)
                .build();
        }

        // 从搜索结果中获取热门景点（评分最高的前6个）
        List<Spot> hotSpots = spots.stream()
            .sorted((a, b) -> b.getRating().compareTo(a.getRating()))
            .limit(6)
            .collect(Collectors.toList());

        // 从搜索结果中获取最新景点（最近添加的前6个）
        List<Spot> newSpots = spots.stream()
            .sorted((a, b) -> b.getCreatedAt().compareTo(a.getCreatedAt()))
            .limit(6)
            .collect(Collectors.toList());

        // 获取分类统计
        Map<String, Long> categories = spots.stream()
            .collect(Collectors.groupingBy(Spot::getCategoryType, Collectors.counting()));

        // 获取类型统计
        Map<String, Long> types = spots.stream()
            .collect(Collectors.groupingBy(Spot::getType, Collectors.counting()));

        // 获取价格区间统计
        Map<String, Long> priceRanges = getPriceRangeStatistics(spots);
        
        // 构建首页响应
        return HomePageResponse.builder()
            .hotSpots(hotSpots.stream().map(this::convertToSimpleSpotResponse).collect(Collectors.toList()))
            .newSpots(newSpots.stream().map(this::convertToSimpleSpotResponse).collect(Collectors.toList()))
            .categories(categories)
            .types(types)
            .priceRanges(priceRanges)
            .total(spots.size())
            .build();
    }

    // 简化版的转换方法，不包含详情信息
    private SpotResponse convertToSimpleSpotResponse(Spot spot) {
        return SpotResponse.builder()
            .id(spot.getId())
            .name(spot.getName())
            .description(spot.getDescription())
            .location(spot.getLocation())
            .price(spot.getPrice())
            .rating(spot.getRating())
            .imageUrls(parseImageUrls(spot.getImageUrls()))
            .type(spot.getType())
            .category_type(spot.getCategoryType())
            .status(spot.getStatus())
            .position_left(spot.getPositionLeft())
            .position_top(spot.getPositionTop())
            .created_at(spot.getCreatedAt())
            .updated_at(spot.getUpdatedAt())
            .build();
    }

    private Map<String, Long> getPriceRangeStatistics(List<Spot> spots) {
        Map<String, Long> priceRanges = new LinkedHashMap<>();
        priceRanges.put("0-100", spots.stream().filter(s -> s.getPrice().compareTo(new BigDecimal("100")) <= 0).count());
        priceRanges.put("100-200", spots.stream().filter(s -> s.getPrice().compareTo(new BigDecimal("100")) > 0 && s.getPrice().compareTo(new BigDecimal("200")) <= 0).count());
        priceRanges.put("200-500", spots.stream().filter(s -> s.getPrice().compareTo(new BigDecimal("200")) > 0 && s.getPrice().compareTo(new BigDecimal("500")) <= 0).count());
        priceRanges.put("500+", spots.stream().filter(s -> s.getPrice().compareTo(new BigDecimal("500")) > 0).count());
        return priceRanges;
    }

    @Override
    public Page<SpotDTO> getSpotList(
        Integer current,
        Integer size,
        String name,
        String type,
        String categoryType,
        String status,
        String location,
        BigDecimal minPrice,
        BigDecimal maxPrice,
        BigDecimal rating
    ) {
        // 创建分页对象
        Page<Spot> page = new Page<>(current, size);
        
        // 构建查询条件
        LambdaQueryWrapper<Spot> queryWrapper = new LambdaQueryWrapper<>();
        
        // 添加查询条件
        if (StringUtils.hasText(name)) {
            queryWrapper.like(Spot::getName, name);
        }
        
        if (StringUtils.hasText(type)) {
            queryWrapper.eq(Spot::getType, type);
        }
        
        if (StringUtils.hasText(categoryType)) {
            queryWrapper.eq(Spot::getCategoryType, categoryType);
        }
        
        if (StringUtils.hasText(status)) {
            queryWrapper.eq(Spot::getStatus, status);
        }
        
        if (StringUtils.hasText(location)) {
            queryWrapper.like(Spot::getLocation, location);
        }
        
        if (minPrice != null) {
            queryWrapper.ge(Spot::getPrice, minPrice);
        }
        
        if (maxPrice != null) {
            queryWrapper.le(Spot::getPrice, maxPrice);
        }
        
        if (rating != null) {
            queryWrapper.ge(Spot::getRating, rating);
        }
        
        // 执行分页查询
        Page<Spot> spotPage = page(page, queryWrapper);
        
        // 转换为 DTO
        Page<SpotDTO> dtoPage = new Page<>(
            spotPage.getCurrent(),
            spotPage.getSize(),
            spotPage.getTotal()
        );
        
        // 转换记录
        List<SpotDTO> records = spotPage.getRecords().stream()
            .map(spot -> {
                SpotDTO dto = new SpotDTO();
                BeanUtils.copyProperties(spot, dto);
                
                // 转换图片 URL 列表
                if (spot.getImageUrls() != null) {
                    dto.setImageUrls(parseImageUrls(spot.getImageUrls()));
                }
                
                // 转换标签列表
                if (spot.getTags() != null) {
                    dto.setTags(parseTags(spot.getTags()));
                }
                
                return dto;
            })
            .collect(Collectors.toList());
        
        dtoPage.setRecords(records);
        
        return dtoPage;
    }

    @Override
    @Transactional
    public Spot createSpot(SpotRequest request) {
        log.info("开始创建景点，请求数据: {}", request);
        
        // 1. 创建景点基本信息
        Spot spot = new Spot();
        BeanUtils.copyProperties(request, spot);
        
        // 2. 处理图片数据
        if (request.getImageUrls() != null && !request.getImageUrls().isEmpty()) {
            try {
                spot.setImageUrls(objectMapper.writeValueAsString(request.getImageUrls()));
            } catch (Exception e) {
                log.error("处理图片数据失败", e);
                throw new BusinessException(400, "图片数据格式错误");
            }
        }
        
        // 3. 处理标签数据
        if (request.getTags() != null && !request.getTags().isEmpty()) {
            try {
                spot.setTags(objectMapper.writeValueAsString(request.getTags()));
            } catch (Exception e) {
                log.error("处理标签数据失败", e);
                throw new BusinessException(400, "标签数据格式错误");
            }
        }
        
        spot.setCreatedAt(LocalDateTime.now());
        spot.setUpdatedAt(LocalDateTime.now());
        
        // 4. 保存景点基本信息
        save(spot);
        log.info("景点基本信息保存成功，ID: {}", spot.getId());
        
        // 5. 保存景点详情
        if (request.getSpotDetail() != null) {
            SpotDetail spotDetail = new SpotDetail();
            spotDetail.setSpotId(spot.getId());
            spotDetail.setDescription(request.getSpotDetail().getDescription());
            spotDetail.setNotice(request.getSpotDetail().getNotice());
            spotDetail.setTrafficInfo(request.getSpotDetail().getTrafficInfo());
            spotDetail.setCategoryDescription(request.getSpotDetail().getCategoryDescription());
            spotDetail.setCreatedAt(LocalDateTime.now());
            spotDetail.setUpdatedAt(LocalDateTime.now());
            spotDetailMapper.insert(spotDetail);
            log.info("景点详情保存成功");
        }
        
        // 6. 保存设施信息
        if (request.getFacilities() != null && !request.getFacilities().isEmpty()) {
            for (SpotFacilityRequest facility : request.getFacilities()) {
                SpotFacility spotFacility = new SpotFacility();
                spotFacility.setSpotId(spot.getId());
                spotFacility.setFacilityName(facility.getFacilityName());
                spotFacility.setFacilityValue(facility.getFacilityValue());
                spotFacility.setCreatedAt(LocalDateTime.now());
                spotFacility.setUpdatedAt(LocalDateTime.now());
                spotFacilityMapper.insert(spotFacility);
            }
            log.info("景点设施保存成功，数量: {}", request.getFacilities().size());
        }
        
        return spot;
    }

    @Override
    @Transactional
    public SpotDTO updateSpot(Long id, SpotRequest request) {
        log.info("开始更新景点，ID: {}, 请求数据: {}", id, request);
        
        // 1. 检查并更新基本信息
        Spot spot = getById(id);
        if (spot == null) {
            throw new BusinessException(404, "景点不存在");
        }
        
        // 2. 更新基本信息
        BeanUtils.copyProperties(request, spot);
        
        // 3. 处理图片数据
        if (request.getImageUrls() != null && !request.getImageUrls().isEmpty()) {
            try {
                spot.setImageUrls(objectMapper.writeValueAsString(request.getImageUrls()));
            } catch (Exception e) {
                log.error("处理图片数据失败", e);
                throw new BusinessException(400, "图片数据格式错误");
            }
        }
        
        // 4. 处理标签数据
        if (request.getTags() != null && !request.getTags().isEmpty()) {
            try {
                spot.setTags(objectMapper.writeValueAsString(request.getTags()));
            } catch (Exception e) {
                log.error("处理标签数据失败", e);
                throw new BusinessException(400, "标签数据格式错误");
            }
        }
        
        spot.setUpdatedAt(LocalDateTime.now());
        updateById(spot);
        log.info("景点基本信息更新成功");
        
        // 5. 更新景点详情
        if (request.getSpotDetail() != null) {
            SpotDetail spotDetail = spotDetailMapper.selectOne(
                new LambdaQueryWrapper<SpotDetail>()
                    .eq(SpotDetail::getSpotId, id)
            );
            
            if (spotDetail == null) {
                // 如果不存在则创建新的
                spotDetail = new SpotDetail();
                spotDetail.setSpotId(id);
                spotDetail.setCreatedAt(LocalDateTime.now());
            }
            
            spotDetail.setDescription(request.getSpotDetail().getDescription());
            spotDetail.setNotice(request.getSpotDetail().getNotice());
            spotDetail.setTrafficInfo(request.getSpotDetail().getTrafficInfo());
            spotDetail.setCategoryDescription(request.getSpotDetail().getCategoryDescription());
            spotDetail.setUpdatedAt(LocalDateTime.now());
            
            if (spotDetail.getId() == null) {
                spotDetailMapper.insert(spotDetail);
            } else {
                spotDetailMapper.updateById(spotDetail);
            }
            log.info("景点详情更新成功");
        }
        
        // 6. 更新设施信息
        if (request.getFacilities() != null) {
            // 先删除原有设施
            spotFacilityMapper.delete(
                new LambdaQueryWrapper<SpotFacility>()
                    .eq(SpotFacility::getSpotId, id)
            );
            
            // 添加新的设施
            if (!request.getFacilities().isEmpty()) {
                for (SpotFacilityRequest facility : request.getFacilities()) {
                    SpotFacility spotFacility = new SpotFacility();
                    spotFacility.setSpotId(id);
                    spotFacility.setFacilityName(facility.getFacilityName());
                    spotFacility.setFacilityValue(facility.getFacilityValue());
                    spotFacility.setCreatedAt(LocalDateTime.now());
                    spotFacility.setUpdatedAt(LocalDateTime.now());
                    spotFacilityMapper.insert(spotFacility);
                }
                log.info("景点设施更新成功，数量: {}", request.getFacilities().size());
            }
        }
        
        // 7. 返回更新后的完整数据
        SpotDTO dto = new SpotDTO();
        BeanUtils.copyProperties(spot, dto);
        dto.setImageUrls(parseImageUrls(spot.getImageUrls()));
        dto.setTags(parseTags(spot.getTags()));
        
        // 获取更新后的详情
        SpotDetail detail = spotDetailMapper.selectOne(
            new LambdaQueryWrapper<SpotDetail>()
                .eq(SpotDetail::getSpotId, id)
        );
        if (detail != null) {
            dto.setSpotDetail(convertToDetailDTO(detail));
        }
        
        // 获取更新后的设施
        List<SpotFacility> facilities = spotFacilityMapper.selectList(
            new LambdaQueryWrapper<SpotFacility>()
                .eq(SpotFacility::getSpotId, id)
        );
        if (!facilities.isEmpty()) {
            dto.setFacilities(convertToFacilityDTOs(facilities));
        }
        
        return dto;
    }

    @Override
    @Transactional
    public void deleteSpot(Long id) {
        // 先删除该景点的所有订单
        orderMapper.deleteBySpotId(id);
        
        // 删除该景点的所有收藏记录
        userFavoriteMapper.deleteBySpotId(id);
        
        // 删除景点相关的详情数据
        spotDetailMapper.deleteBySpotId(id);
        
        // 删除景点相关的设施数据
        spotFacilityMapper.deleteBySpotId(id);
        
        // 最后删除景点本身
        removeById(id);
    }

    @Override
    public void addFavorite(Long userId, Long spotId) {
        // 这个方法应该在 UserService 中实现，这里可以抛出异常
        throw new BusinessException(400, "此方法应在 UserService 中实现");
    }

    @Override
    public void removeFavorite(Long userId, Long spotId) {
        // 这个方法应该在 UserService 中实现，这里可以抛出异常
        throw new BusinessException(400, "此方法应在 UserService 中实现");
    }

    @Override
    public List<SpotResponse> getUserFavorites(Long userId, Integer pageNum, Integer pageSize) {
        // 这个方法应该在 UserService 中实现，这里可以抛出异常
        throw new BusinessException(400, "此方法应在 UserService 中实现");
    }

    @Override
    public Page<SpotDTO> getSpotPage(Page<Spot> page, LambdaQueryWrapper<Spot> wrapper) {
        // 1. 先查询基本信息
        Page<Spot> spotPage = page(page, wrapper);
        Page<SpotDTO> dtoPage = new Page<>();
        BeanUtils.copyProperties(spotPage, dtoPage, "records");

        // 2. 转换并补充详细信息
        List<SpotDTO> records = spotPage.getRecords().stream()
            .map(spot -> {
                SpotDTO dto = new SpotDTO();
                BeanUtils.copyProperties(spot, dto);
                
                // 处理图片URLs
                dto.setImageUrls(parseImageUrls(spot.getImageUrls()));
                
                // 处理标签
                dto.setTags(parseTags(spot.getTags()));
                
                // 获取景点详情
                SpotDetail detail = spotDetailMapper.selectOne(
                    new LambdaQueryWrapper<SpotDetail>()
                        .eq(SpotDetail::getSpotId, spot.getId())
                );
                if (detail != null) {
                    dto.setSpotDetail(convertToDetailDTO(detail));
                }
                
                // 获取设施信息
                List<SpotFacility> facilities = spotFacilityMapper.selectList(
                    new LambdaQueryWrapper<SpotFacility>()
                        .eq(SpotFacility::getSpotId, spot.getId())
                );
                if (!facilities.isEmpty()) {
                    dto.setFacilities(convertToFacilityDTOs(facilities));
                }
                
                return dto;
            })
            .collect(Collectors.toList());
        
        dtoPage.setRecords(records);
        return dtoPage;
    }

    private SpotDetailDTO convertToDetailDTO(SpotDetail detail) {
        return SpotDetailDTO.builder()
            .id(detail.getId())
            .spotId(detail.getSpotId())
            .description(detail.getDescription())
            .notice(detail.getNotice())
            .trafficInfo(detail.getTrafficInfo())
            .categoryDescription(detail.getCategoryDescription())
            .createdAt(detail.getCreatedAt())
            .updatedAt(detail.getUpdatedAt())
            .build();
    }

    private List<FacilityDTO> convertToFacilityDTOs(List<SpotFacility> facilities) {
        return facilities.stream()
            .map(facility -> FacilityDTO.builder()
                .id(facility.getId())
                .spotId(facility.getSpotId())
                .facilityName(facility.getFacilityName())
                .facilityValue(facility.getFacilityValue())
                .createdAt(facility.getCreatedAt())
                .updatedAt(facility.getUpdatedAt())
                .build())
            .collect(Collectors.toList());
    }
} 